#include "FunTrace.h"
#include <Commdb.h> //TCommDbConnPref
#include <Commdbconnpref.h> //TCommDbConnPref
#include <stringpool.h> //RStringPool
#include <e32base.h>
#include <S32FILE.H>
#include <http.h>
#include <aknglobalnote.h> 
#include <aknnotewrappers.h> 
#include "WLANSettings/wlancdbcols.h"
#include "IapConnectionManager.h"

#include "SingaporeBusDocument.h"

static void PrintNoteL(TRefByValue<const TDesC> aFormat, ...)
    {
    VA_LIST list;
    VA_START(list, aFormat);
    TBuf<256> buf;
    buf.FormatList(aFormat, list);
    VA_END(list);
	CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
	globalNote->ShowNoteL(EAknGlobalInformationNote, buf); 
    CleanupStack::PopAndDestroy(globalNote);
    }


static void MessageBox(const TDesC& a_string)
	{
	CAknInformationNote* note = new (ELeave) CAknInformationNote(ETrue);
	note->ExecuteLD(a_string);	
	User::After(100000);
	}



MIapConnectionManagerCallback::~MIapConnectionManagerCallback()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	}

CIapConnectionManager::~CIapConnectionManager()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	delete iActiveConnectionMonitor;
	delete iConnectionActiveHelper;
	delete iConnectionProgressNotificationActiveHelper;
	iNearbyWlanNetworkNames.Close();
	iConnectionMonitor.Close();
	iSubscribersList.Close();
	iSession.Close(); // has to be this order it seems
	iConnection.Close();
	iSockServ.Close();
	}
CIapConnectionManager::CIapConnectionManager()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	// TODO Auto-generated constructor stub
	iActiveConnectionMonitor = NULL;
	iIapPriorityList = NULL;
	}

CIapConnectionManager* CIapConnectionManager::NewL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CIapConnectionManager* ret = NewLC();
	CleanupStack::Pop(ret);
	return ret;	
	}
CIapConnectionManager* CIapConnectionManager::NewLC()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CIapConnectionManager* ret = new (ELeave) CIapConnectionManager;
	CleanupStack::PushL(ret);
	ret->ConstructL();
	return ret;
	}

void CIapConnectionManager::ConstructL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	iSession.OpenL();
	iConnectionActiveHelper = CActiveHelper<RConnection*>::NewL();
	
	User::LeaveIfError(iSockServ.Connect(16));
	User::LeaveIfError(iSockServ.ShareAuto());
	User::LeaveIfError(iConnection.Open(iSockServ));
	
	iConnectionProgressNotificationActiveHelper = CActiveHelper<TNifProgressBuf*>::NewL();
	iConnection.ProgressNotification(iProgBuf, iConnectionProgressNotificationActiveHelper->iStatus);
	iConnectionProgressNotificationActiveHelper->SetActive(this, &iProgBuf);

	RStringPool strP = iSession.StringPool();
	RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
	connInfo.SetPropertyL ( strP.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable() ), THTTPHdrVal (iSockServ.Handle()) );
	TInt connPtr = REINTERPRET_CAST(TInt, &iConnection);
	connInfo.SetPropertyL ( strP.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable() ), THTTPHdrVal (connPtr) );
	
	iActiveConnectionMonitor = CActiveHelper<RConnectionMonitor*>::NewL();
	User::LeaveIfError(iConnectionMonitor.ConnectL());
	User::LeaveIfError(iConnectionMonitor.NotifyEventL( *this ));
	}

void CIapConnectionManager::ResetConnectionL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iConnection.Close();
	User::LeaveIfError(iConnection.Open(iSockServ));
	iConnectionProgressNotificationActiveHelper->Cancel();
	iConnection.ProgressNotification(iProgBuf, iConnectionProgressNotificationActiveHelper->iStatus);
	iConnectionProgressNotificationActiveHelper->SetActive(this, &iProgBuf);
	}


void CIapConnectionManager::NotifySubscribers(TInt iStage, TInt iError)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	for(int i = 0 ; i < iSubscribersList.Count() ; ++i)
		{
		iSubscribersList[i]->MIapConnectionManagerCallbackRunL(iStage, iError);
		}	
	}
void CIapConnectionManager::SubscribeL(MIapConnectionManagerCallback* aTarget)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	int i;
	for(i = 0 ; i < iSubscribersList.Count() && iSubscribersList[i] != aTarget; ++i);
	if(i == iSubscribersList.Count())
		iSubscribersList.AppendL(aTarget);
	}
void CIapConnectionManager::UnSubscribeL(MIapConnectionManagerCallback* aTarget)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	int i;
	for(i = 0 ; i < iSubscribersList.Count() && iSubscribersList[i] != aTarget; ++i);
	if(i != iSubscribersList.Count())
		iSubscribersList.Remove(i);	
	}


void CIapConnectionManager::ConnectL(MIapConnectionManagerCallback* aTarget)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	SubscribeL(aTarget);
	
	iActiveConnectionMonitor->Cancel();
	iConnectionMonitor.GetPckgAttribute(EBearerIdWLAN, 0, KNetworkNames, iPkgNetworks, iActiveConnectionMonitor->iStatus); 
	iActiveConnectionMonitor->SetActive(this, &iConnectionMonitor);
	}


void CIapConnectionManager::SetIapPriorityList(RArray<TUint32>* aIapPriorityList)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	iIapPriorityList = aIapPriorityList;	
	}

void CIapConnectionManager::EventL (const CConnMonEventBase &aConnMonEvent)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	switch ( aConnMonEvent.EventType() )
	{
		case EConnMonDeleteConnection:
		{
		// Some Implementation 
		break;
		}
		case  EConnMonNetworkStatusChange:
		{
		// Some Implementation
		break;
		}
		case  EConnMonConnectionStatusChange:
		{
		// Some Implementation
		break;
		}
		case  EConnMonBearerChange:
		{
		// Some Implementation
		break;
		}
		default:
		break;
	}


}
/*TInt CIapConnectionManager::ConnectL(RHTTPSession& iSession)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	iConnectionMonitor.GetPckgAttribute(EBearerIdWLAN, 0, KNetworkNames, iPkgNetworks, iActiveConnectionMonitor->iStatus); 
	iActiveConnectionMonitor->SetActive(this, &iConnectionMonitor);
	}*/

/*
 * http://discussion.forum.nokia.com/forum/showthread.php?t=135118
 * 
 HBufC * apn_name = view->ReadLongTextLC( TPtrC( GPRS_APN) );

view->ReadTextL((TPtrC)GPRS_APN, name);
*/

void CIapConnectionManager::MActiveHelperCallbackRunL(CActiveHelper<TNifProgressBuf*>* aActiveHelper, TNifProgressBuf* aUserData)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	iConnectionProgressNotificationActiveHelper->Cancel();
	iConnection.ProgressNotification(iProgBuf, aActiveHelper->iStatus);
	NotifySubscribers(iProgBuf().iStage, iProgBuf().iError);
	iConnectionProgressNotificationActiveHelper->SetActive(this, &iProgBuf);
	}
TInt CIapConnectionManager::MActiveHelperCallbackRunError(CActiveHelper<TNifProgressBuf*>* aActiveHelper, TNifProgressBuf* aUserData, TInt aError)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	}
void CIapConnectionManager::MActiveHelperCallbackDoCancel(CActiveHelper<TNifProgressBuf*>* aActiveHelper, TNifProgressBuf* aUserData)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	iConnection.CancelProgressNotification();
	}


void CIapConnectionManager::MActiveHelperCallbackRunL(CActiveHelper<RConnectionMonitor*>* aActiveHelper, RConnectionMonitor* aUserData)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);

	iNearbyWlanNetworkNames.Reset();
	for(TUint i = 0; i<iPkgNetworks().iCount; i++)
		{
		TBuf<100> buf;
		buf.Copy(iPkgNetworks().iNetwork[i].iName);
		iNearbyWlanNetworkNames.AppendL(buf);
		}
	
	iIapPriorityListCurrentIndex = 0;
	
	TInt err = TryNextIap();
	if(err != KErrNone)
		NotifySubscribers(KConnectionUninitialised, err);
	
	}
TInt CIapConnectionManager::MActiveHelperCallbackRunError(CActiveHelper<RConnectionMonitor*>* aActiveHelper, RConnectionMonitor* aUserData, TInt aError)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	}
void CIapConnectionManager::MActiveHelperCallbackDoCancel(CActiveHelper<RConnectionMonitor*>* aActiveHelper, RConnectionMonitor* aUserData)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	}

TInt CIapConnectionManager::TryNextIap()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	TBool connectionStarted = EFalse;
	for( ; !connectionStarted && iIapPriorityList && iIapPriorityListCurrentIndex < iIapPriorityList->Count() ; ++iIapPriorityListCurrentIndex)
		{
		// http://wiki.forum.nokia.com/index.php/How_to_retrive_SSID_used_in_WLAN_IAP_and_IAP_used_by_VPN_IAP_programmatically
		TBool isWLAN = EFalse; 
		TBuf<100> name;
		TBuf<100> ssid;
		{
			CCommsDatabase* commDB = CCommsDatabase::NewL(ETrue);
			CleanupStack::PushL(commDB);
			CCommsDbTableView* view = commDB->OpenViewMatchingUintLC(TPtrC(IAP),TPtrC(COMMDB_ID), (*iIapPriorityList)[iIapPriorityListCurrentIndex]);

			view->ReadTextL(TPtrC(COMMDB_NAME), name);
						
			TUint32 bearer;
			view->ReadUintL(TPtrC(IAP_BEARER), bearer);
			isWLAN = (bearer == 1);
						
			if (isWLAN && view->GotoFirstRecord() == KErrNone)
			{
				TUint32 wlanId;
				view->ReadUintL(TPtrC(IAP_SERVICE), wlanId);
#ifndef __WINS__
				CCommsDbTableView * wlanServiceTable = commDB->OpenViewMatchingUintLC(TPtrC(WLAN_SERVICE), TPtrC(WLAN_SERVICE_ID), wlanId);
				if (wlanServiceTable->GotoFirstRecord() == KErrNone)
					wlanServiceTable->ReadTextL(TPtrC(WLAN_SSID), ssid);
				CleanupStack::PopAndDestroy(wlanServiceTable);
#endif
			}
			CleanupStack::PopAndDestroy(view);
			CleanupStack::PopAndDestroy(commDB);			
		}
		int nearbyIt;
		for(nearbyIt = 0 ; nearbyIt < iNearbyWlanNetworkNames.Count() && iNearbyWlanNetworkNames[nearbyIt] != ssid ; ++nearbyIt);
		if(!isWLAN || nearbyIt != iNearbyWlanNetworkNames.Count())
			{
			{
				TBuf<256> buf;
				buf.Format(_L("Connecting via %S..."), &name);
				CAknInformationNote* note = new ( ELeave ) CAknInformationNote();
				note->ExecuteLD(buf);
			}
			TCommDbConnPref pref;
			pref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
			pref.SetDirection(ECommDbConnectionDirectionOutgoing);
#ifdef DeprecatedCDMA2000
	#define KCommDbBearerCdma2000 DeprecatedCDMA2000
#endif
			pref.SetBearerSet( ECommDbBearerGPRS | ECommDbBearerCdma2000 | ECommDbBearerLAN | ECommDbBearerCSD );
			pref.SetIapId((*iIapPriorityList)[iIapPriorityListCurrentIndex]);
			iConnectionActiveHelper->Cancel();
			iConnection.Start(pref, iConnectionActiveHelper->iStatus);
			iConnectionActiveHelper->SetActive(this, &iConnection);
			connectionStarted = ETrue;
			}
		}
		for ( ; !connectionStarted && iIapPriorityList && iIapPriorityListCurrentIndex == iIapPriorityList->Count() ; ++iIapPriorityListCurrentIndex)
			{
			TCommDbConnPref pref;
			pref.SetDialogPreference(ECommDbDialogPrefPrompt);
			pref.SetDirection(ECommDbConnectionDirectionOutgoing);
			iConnectionActiveHelper->Cancel();
			iConnection.Start(pref, iConnectionActiveHelper->iStatus);
			iConnectionActiveHelper->SetActive(this, &iConnection);
			connectionStarted = ETrue;
			}
		return connectionStarted ? KErrNone : KErrNotFound;
	}

TBool CIapConnectionManager::IsConnecting()
	{
	return iActiveConnectionMonitor->IsActive() || iConnectionActiveHelper->IsActive();
	}

void CIapConnectionManager::MActiveHelperCallbackRunL(CActiveHelper<RConnection*>* aActiveHelper, RConnection* aUserData)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	TInt err = aActiveHelper->iStatus.Int();
	switch(err)
		{
		case KErrNone:
		case KErrAlreadyExists:
			{
			NotifySubscribers(-1, aActiveHelper->iStatus.Int());
			}
			break;
		default:
			{
			if(TryNextIap() != KErrNone)
				NotifySubscribers(-1, aActiveHelper->iStatus.Int());
			}
			break;
		}	
	}
TInt CIapConnectionManager::MActiveHelperCallbackRunError(CActiveHelper<RConnection*>* aActiveHelper, RConnection* aUserData, TInt aError)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	}
void CIapConnectionManager::MActiveHelperCallbackDoCancel(CActiveHelper<RConnection*>* aActiveHelper, RConnection* aUserData)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	}


/*
The list of available WLAN networks and their instant signal strength can be obtained by using the interfaces provided by the Connection Monitor Server API.

Here is an example of how the API can be used:

#include <rconnmon.h>

void CWlanTest:: ListNetworksAndSignalL(CDesCArraySeg& aNetworks)

{

_LIT(KNetInfo, "Network: %S\tSignal: %d");

TBuf<32> netName;

TBuf<100> line;

RConnectionMonitor monitor;

TPckgBuf<TConnMonNetworkNames> pkgNetworks;

// establish connection with the monitor server

monitor.ConnectL();

// prepare leave clean-up

CleanupClosePushL(monitor);

TRequestStatus status;

// get the list of available networks

monitor.GetPckgAttribute(EBearerIdWLAN, 0, KNetworkNames, pkgNetworks, status); 

// suspend thread until the info is retrieved

// production code should use active objects

User::WaitForRequest( status ) ;

// leave if the asynchronous method returned an error

User::LeaveIfError(status.Int());

// reset networks list

aNetworks.Reset();

// add retrieved networks to the list

for(TUint i=0; i<pkgNetworks().iCount; i++)

{

netName.Copy(pkgNetworks().iNetwork[i].iName); 

line.Format(KNetInfo, &netName, pkgNetworks().iNetwork[i].iSignalStrength);

aNetworks.AppendL(line);

}

// close server session

CleanupStack::PopAndDestroy(&monitor);

}

Note:

- Link against: ConnMon.lib

- S60 3rd Edition-specific capability needed: NetworkServices  

 */

/*
Overview 
How can I determine active connections? 

Description 
RConnection::EnumerateConnections() returns the number of active connections and RConnection::GetConnectionInfo() can be used to get the net ID and IAP ID of each connection. Symbian v7.0s supports multiple simultaneous active PDP contexts. 

Retrieved from "http://wiki.forum.nokia.com/index.php/TSS000056_-_How_can_I_determine_active_connections%3F"
 */


